#pragma once
#include <glm/gtc/matrix_transform.hpp>
#include "Struct.h"

/** @note All PlatUtil class must be exactly pure common util, must not include functional class ! example: must not include 'Global.h' */
class GeoUtil {
public:
	static void createSolidLine(CVector<P>& outVertices, const LineEq& eq);
	static void createDashedLine(CVector<P>& outVertices, CVector<UInt>& outIndices, const LineEq& eq, float slopeRatioByWidth = 0, float vOffset = 0);

	static P getPointOnVector(const P& vectorAcrossPoint, float vectorEulerRotX, float D, bool rayFromP = true);

	static void createCircle(CVector<P>& outVertices, const P& center, float radius, int composedPointCnt) { createEllipse(outVertices, center, 2*radius, 2*radius, composedPointCnt); }
	static void createCircleXY(CVector<Vec3>& outVertices, const Vec3& center, float radius, int composedPointCnt) { createEllipseXY(outVertices, center, 2*radius, 2*radius, composedPointCnt); }

	static void createEllipse(CVector<P>& outVertices, const P& center, float hAxis, float vAxis, int composedPointCnt);
	static void createEllipseXY(CVector<Vec3>& outVertices, const Vec3& center, float hAxis, float vAxis, int composedPointCnt);
	static void createLineEllipse(CVector<P>& outVertices, const LineEq& eq, float centerZ, float hAxis, float vAxis, HDir hdir);
	static bool createLineArrow(CVector<P>& outVertices, const LineEq& eqL, const LineEq& eqR, float topZ, float zhicheWidth, bool isNotMiddle = true);
	static void createRoadBg(CVector<P>& outAllVertices, const CVector<LineEq>& eqsFromLToR, RoadBgStyle style);
	static void createFilledLane(CVector<P>& outAllVertices, const LineEq& eqL, const LineEq& eqR) { createRoadBg(outAllVertices, CVector<LineEq>() << eqL << eqR, RoadBgStyle::Fill);  }
	static void createRoadEdge(CVector<Vec3>& outVertices, CVector<UInt>& outIndices, const LineEq& eq, float edgeW, float edgeH, float vOffset = 0);
	static void createRoadEdge(CVector<Vec3>& outVertices, const LineEq& eq, float edgeW, float edgeH);
	static void createDashedRect(CVector<P>& outVertices, CVector<UInt>& outIndices, const P& rectCenter, float rectWidth, float rectLength, float dashLen, float dashBold);

	static float getXByEquation(const LineEq& eq, float z) { float x; getByEquation(eq, z, &x); return x; }
	static float getDxByEquation(const LineEq& eq, float z) { float dx; getByEquation(eq, z, nullptr, &dx); return dx; }

	static P getLineIntersection(const Pair<P, P>& line1, const Pair<P, P>& line2);

	static Mat createPerspectiveMatrix(float fovy, float aspect, float near, float far);

	static bool checkIfOnRayCCWSweepingSide(const P& point, const P& rayFromPoint, const P& rayToPoint);

	static P mapTo3DXZPlane(const Vec2& screenPos, const CSize& screenSize, const Mat& viewMatrix, const Mat& projectionMatrix);

	static P mapToOrtho3DXZPlane(const Vec2& screenPos, const CSize& screenSize, const Mat& viewMatrix, const Mat& orthoProjMatrix, const Vec4& viewport = Vec4(0, 0, 1, 1));

private:
	GeoUtil() = default;

	static void createOneDimensionalSolidLinePoints(CVector<P>& outVertices, const LineEq& eq, float vStep = Config::Line_PointsZStep);
	static void createOneDimensionalDashedLinePoints(CVector<CVector<P>>& outVerticesList, const LineEq& eq, float segLen, float segInterval, float vStep = Config::Line_PointsZStep, float vOffset = 0);

	static void getByEquation(const LineEq& eq, float z, float* x = nullptr, float* dx = nullptr);

	static void createBezierPoints(CVector<P>& outVertices, const CVector<P>& C, int pointsNum);
	static P getBezierPoint(const CVector<P>& C, float t);
};